package com.turing.post.test;

import java.math.BigDecimal;
import java.math.BigInteger;
import java.math.RoundingMode;
import java.util.HashMap;
import java.util.Map;

//package com.turing.post.test;
//
//import java.security.NoSuchAlgorithmException;
//import java.security.Security;
//import java.security.spec.InvalidKeySpecException;
//
//import javax.crypto.Cipher;
//import javax.crypto.SecretKey;
//import javax.crypto.SecretKeyFactory;
//import javax.crypto.spec.IvParameterSpec;
//import javax.crypto.spec.SecretKeySpec;
//
//import com.turing.post.util.HexDump;
//
//public class posMacCalc {
//	static {
//		Security.addProvider(new BouncyCastleProvider());
//	}
//
//	public static void main(String[] args) throws Exception {
//		// zak(mackey)
//		byte[] MACKEY = new byte[] { 31, 31, 31, 31, 31, 31, 31, 31 };
//		// 待计算数据
//		byte[] data = new byte[] { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
//				0x00 };
//		// 进行分组
//		int group = (data.length + (8 - 1)) / 8;
//		// 偏移量
//		int offset = 0;
//		// 输入计算数据
//		byte[] edata = null;
//		for (int i = 0; i < group; i++) {
//			byte[] temp = new byte[8];
//			if (i != group - 1) {
//				System.arraycopy(data, offset, temp, 0, 8);
//				offset += 8;
//			} else {// 只有最后一组数据才进行填充0x00
//				System.arraycopy(data, offset, temp, 0, data.length - offset);
//			}
//
//			if (i != 0) {// 只有第一次不做异或
//				temp = XOR(edata, temp);
//			}
//			edata = desedeEn(MACKEY, temp);
//		}
//		System.out.println(java.util.Arrays.toString(byte2Int(edata)));
//		System.out.println(HexDump.toHex(edata));
//	}
//
//	public static byte[] XOR(byte[] edata, byte[] temp) {
//		byte[] result = new byte[8];
//		for (int i = 0, j = result.length; i < j; i++) {
//			result[i] = (byte) (edata[i] ^ temp[i]);
//		}
//		return result;
//	}
//
//	public static int[] byte2Int(byte[] data) {
//		int[] result = new int[data.length];
//
//		for (int i = 0; i < data.length; i++) {
//			if (data[i] < 0) {
//				result[i] = data[i] + 256;
//			} else {
//				result[i] = data[i];
//			}
//		}
//
//		return result;
//	}
//
//	public static byte[] desedeEn(byte[] key, byte[] data) {
//		byte[] result = null;
//		try {
//			SecretKey secretKey = getSecretKeySpec(key);
//			Cipher cipher = Cipher.getInstance("DES/CBC/NoPadding", "BC");
//
//			cipher.init(Cipher.ENCRYPT_MODE, secretKey, new IvParameterSpec(
//					new byte[8]));
//			// 初始化向量为0,即异或不改变原始数据
//
//			result = cipher.doFinal(data);
//		} catch (Exception e) {
//			e.printStackTrace();
//		}
//		return result;
//	}
//
//	private static SecretKey getSecretKeySpec(byte[] keyB)
//			throws NoSuchAlgorithmException, InvalidKeySpecException {
//		SecretKeyFactory secretKeyFactory = SecretKeyFactory.getInstance("Des");
//		SecretKeySpec secretKeySpec = new SecretKeySpec(keyB, "Des");
//		return secretKeyFactory.generateSecret(secretKeySpec);
//	}
//}

public class posMacCalc {
	/**
	 * 计算Q值最大的1个卡号
	 * 
	 * @param alreadypaid
	 * @param allcardamt
	 * @return
	 */
	public static String getMaxQValue(Map<String, BigInteger> alreadypaid,
			Map<String, BigInteger> allcardamt) {
		BigDecimal curmax = BigDecimal.ZERO;
		String cardNo = null;

		for (Map.Entry<String, BigInteger> allentry : allcardamt.entrySet()) {
			String cardno = allentry.getKey();
			BigInteger allamt = allentry.getValue();
			BigInteger allseat = alreadypaid.get(cardno);
			if (allseat == null)
				allseat = BigInteger.ZERO;
			allseat = allseat.add(BigInteger.ONE);
			BigDecimal allamt_q = new BigDecimal(allamt.toString());
			allamt_q = allamt_q.multiply(allamt_q);
			BigDecimal seat_q = new BigDecimal(allseat.toString())
					.multiply(new BigDecimal(allseat.add(BigInteger.ONE)
							.toString()));
			BigDecimal cmax = allamt_q
					.divide(seat_q, 6, RoundingMode.HALF_DOWN);
			if (cmax.compareTo(curmax) > 0) {
				cardNo = cardno;
				curmax = cmax;
			}
		}

		return cardNo;
	}

	/**
	 * 将指定业务类型发生额公平分配到map中
	 * 
	 * @param businessType
	 *            业务类型
	 * @param bsamt
	 *            业务类型发生额
	 * @param allcardamt
	 *            卡号发生额( "SCORE" || "OTHER" || "CARDNO" )
	 */
	public static Map<String, BigInteger> distributePaid(String businessType,
			BigInteger bsamt, Map<String, BigInteger> allcardamt) {

		Map<String, BigInteger> alreadypaid = new HashMap<String, BigInteger>();

		// 删除为0的入口数据
		if (allcardamt.size() == 0)
			return alreadypaid;

		// 计算allcardamt的总和
		BigInteger total = BigInteger.ZERO;
		
		for (Map.Entry<String, BigInteger> tot : allcardamt.entrySet())
			total = total.add(tot.getValue());

		if (total.compareTo(BigInteger.ZERO) <= 0)
			return alreadypaid;

		// 先平均分配整数部分
		// 本笔业务发生额折算到每分钱的贡献度
		BigDecimal bd = new BigDecimal(bsamt.toString()).divide(
				new BigDecimal(total.toString()), 10, RoundingMode.HALF_DOWN);

		for (Map.Entry<String, BigInteger> allentry : allcardamt.entrySet()) {
			String cardno = allentry.getKey();
			BigInteger cardamt = allentry.getValue();
			BigInteger curamt = bd.multiply(new BigDecimal(cardamt.toString()))
					.setScale(0, RoundingMode.HALF_UP).toBigInteger();
			// 折算后不足1分钱,继续
			if (curamt.compareTo(BigInteger.ZERO) <= 0)
				continue;
			BigInteger oldamt = alreadypaid.remove(cardno);
			if (oldamt == null)
				oldamt = BigInteger.ZERO;
			if (cardamt.compareTo(oldamt.add(curamt)) < 0)
				curamt = cardamt.subtract(oldamt);
			curamt = curamt.compareTo(bsamt) <= 0 ? curamt : bsamt;
			oldamt = oldamt.add(curamt);
			bsamt = bsamt.subtract(curamt);
			alreadypaid.put(cardno, oldamt);
			// 如果已经分配完毕
			if (bsamt.compareTo(BigInteger.ZERO) <= 0)
				break;
		}

		// 分配剩余部分,按Q值法,每次分配1分钱
		while (bsamt.compareTo(BigInteger.ZERO) > 0) {
			String cardno = getMaxQValue(alreadypaid, allcardamt);
			BigInteger oldamt = alreadypaid.remove(cardno);
			if (oldamt == null)
				oldamt = BigInteger.ZERO;
			oldamt = oldamt.add(BigInteger.ONE);
			alreadypaid.put(cardno, oldamt);
			bsamt = bsamt.subtract(BigInteger.ONE);
		}

		// 对alreadypaid中的每个记录,将allcardamt中的记录减去
		for (Map.Entry<String, BigInteger> allentry : alreadypaid.entrySet()) {
			String cardno = allentry.getKey();
			BigInteger amt = allentry.getValue();
			BigInteger oldamt = allcardamt.remove(cardno);
			if (oldamt == null)
				continue;
			oldamt = oldamt.subtract(amt);
			if (oldamt.compareTo(BigInteger.ZERO) <= 0)
				continue;
			allcardamt.put(cardno, oldamt);
		}

		return alreadypaid;
	}
	
	public static void main(String[] args) throws Exception {
		
		Map<String, BigInteger> allcardamt = new HashMap<String, BigInteger>();
		allcardamt.put("C", BigInteger.valueOf(1500));
		allcardamt.put("D", BigInteger.valueOf(2000));
		allcardamt.put("SCORE", BigInteger.valueOf(400));
		allcardamt.put("OTHER", BigInteger.valueOf(100));
		Map<String, BigInteger> mapa = distributePaid("A",
				BigInteger.valueOf(1000),  allcardamt );
		for (Map.Entry<String, BigInteger> en : mapa.entrySet()){
			System.out.println(en.getKey() + ":" + en.getValue().toString());
		}
		
		mapa = distributePaid("B",
				BigInteger.valueOf(3000),  allcardamt );
		for (Map.Entry<String, BigInteger> en : mapa.entrySet()){
			System.out.println(en.getKey() + ":" + en.getValue().toString());
		}

	}
}